﻿#region Header
// ------------------------ Licence / Copyright ------------------------
// 
// ScrumTable for Scrum Meeting Support
// Copyright © HSR - Hochschule für Technik Rapperswil
// All Rights Reserved
// 
// Author:
//  Michael Gfeller Silvan Gehrig Patrick Boos
// 
// ---------------------------------------------------------------------
#endregion

#region Usings

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows;
using System;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
using ScrumTable.Config.ConfigManagement;
using ScrumTable.UI.View.Controls;
using ScrumTable.UI.View.CustomControl;
using ScrumTable.UI.View.Extension;
using ScrumTable.UI.View.Localization;
using ScrumTable.UI.View.Util;
using ScrumTable.UI.View.WinTouch.UserControls.Tool;
using ScrumTable.UI.View.WinTouch.UserControls.View;
using ScrumTable.UI.ViewModel;
using System.Linq;
using ScrumTable.BL.DM.DataManagement;
using ScrumTable.Common.Unity;
using ScrumTable.UI.ViewModel.Data;
using System.Windows.Shapes;
using ScrumTable.UI.ViewModel.Extension;

#endregion

namespace ScrumTable.UI.View.WinTouch.UserControls
{

  
    /// <summary>
    /// Shows a User Story as a Stack: Shows the User-Story and all childs (tasks)
    /// 
    /// </summary>
    public partial class StackedUserStoryControl : IDropUserControl
{


        #region Declarations
        //--------------------------------------------------------------------
        // Declarations
        //--------------------------------------------------------------------
        private ScrumState _storyState;
        private const double MaxHours=100;
       
         
        
        #endregion

        #region Properties
        //--------------------------------------------------------------------
        // Properties
        //--------------------------------------------------------------------

        public ObservableCollection<IScrumItemViewModel<DomainBase>> PlacedControls { get; set; }


        /// <summary>
        /// contains the number of other controls.
        /// </summary>
        public int NumbersOfOtherControls { get; set; }

        /// <summary>
        /// DependencyProperty for UserStorie.
        /// </summary>
        public static readonly DependencyProperty IsExpanedProperty =
            DependencyProperty.Register("IsExpaned",
                                        typeof(bool),
                                        typeof(StackedUserStoryControl),
                                        new UIPropertyMetadata(true, new PropertyChangedCallback(OnIsExpandedChanged)));

        /// <summary>
        /// Shows the control in a expaned mode, or not...
        /// </summary>
        /// <value></value>
        public bool IsExpaned
        {
            get { return (bool)GetValue(IsExpanedProperty); }
            set { SetValue(IsExpanedProperty, value); }
        }
       
 
        /// <summary>
        /// DependencyProperty for UserStory.
        /// </summary>
        public static readonly DependencyProperty UserStoryProperty =
            DependencyProperty.Register("StackedUserStory",
                                        typeof(UserStoryViewModel),
                                        typeof(StackedUserStoryControl),
                                        new UIPropertyMetadata(null));

        /// <summary>
        /// The Control shows all childs (Tasks) of this UserStory 
        /// </summary>
        /// <value></value>
        public UserStoryViewModel StackedUserStory
        {
            get
            {
                return (UserStoryViewModel)GetValue(UserStoryProperty);
            }
            set
            {
                SetValue(UserStoryProperty, value);
                Init();

                //TODO optimize with collection change but now it works with the collection change event
                //StackedUserStory.Tasks.CollectionChanged += OnTaskBugCollectionChanged;
                //StackedUserStory.Bugs.CollectionChanged += OnTaskBugCollectionChanged;
            }
        }



        /// <summary>
        /// if  StoryState state == UserStory.State the userStroy is placed on this control.
        /// </summary>
        /// <value>The state of the story.</value>
        public ScrumState StoryState
        {
            get
            {
                return _storyState;
            }
            set
            {
                _storyState = value;
                Init();
            }
        }
        #endregion


        #region Constructors / Destructor
        //--------------------------------------------------------------------
        // Constructors / Destructor
        //--------------------------------------------------------------------


        /// <summary>
        /// Initializes a new instance of the <see cref="StackedUserStoryControl"/> class.
        /// </summary>
        public StackedUserStoryControl()
        {
            DataContextChanged += OnStackedUserStoryControlDataContextChanged;
            PlacedControls = new ObservableCollection<IScrumItemViewModel<DomainBase>>();
            Loaded += OnUserStoryControlLoaded;
            InitializeComponent();
            ScrumViewModelData scrumData = ((AppScreen)(Application.Current.MainWindow)).Container.Resolve<ScrumViewModelData>();
            scrumData.DataContext.ElementChanged += OnContextElementChanged;
            scrumData.DataContext.CollectionChanged += OnContextCollectionChanged;
            
        }

     
       
      
        #endregion
        #region Methods
        //--------------------------------------------------------------------
        // Methods
        //--------------------------------------------------------------------
   

        private static void OnIsExpandedChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
           ((StackedUserStoryControl)(sender)).Init();
        }

        //TODO move into an other file? & Optimize 
        private void Init()
        {
            if (Grid == null) { return; }
            Grid.Children.Clear();
            Cross.Visibility = Visibility.Hidden;
            if (StackedUserStory != null )
            {
                if (StackedUserStory.State == StoryState)
                {
                    Grid.Background = new SolidColorBrush(Colors.AliceBlue) { Opacity = 0.7 };
                }
                else
                {
                    Grid.Background = Brushes.Transparent;
                }
                var scrumData = ((AppScreen) Application.Current.MainWindow).Container.Resolve<ScrumViewModelData>();
                var tasks = (from x in StackedUserStory.Tasks where x.State == StoryState && scrumData.ContainsFilter(x) select new TaskViewModel(x)).ToList();
                var bugs =(from x in StackedUserStory.Bugs where x.State == StoryState && scrumData.ContainsFilter(x) select new BugViewModel(x)).ToList();
                var items = tasks.Union(bugs.Cast<IScrumItemViewModel<DomainBase>>());
                if (IsExpaned)
                {
                    ItemContainerControl.Visibility = Visibility.Visible;
                    CreateChilds(items.ToList());
                }
                else
                {
                    ItemContainerControl.Visibility = Visibility.Collapsed;
                    CreateBugsChildsSmall(bugs);
                    CreateTaskChildsSmall(tasks);
                }
            }
        }

        private void CreateBugsChildsSmall(IEnumerable<BugViewModel> bugs)
        {
            StackPanel stackPanel = new StackPanel() { Orientation = Orientation.Horizontal };
            foreach (var bugViewModel in bugs)
            {
                stackPanel.Children.Add(
                    new Label()
                        {
                            Background = (Brush) Application.Current.Resources["IconBug"],
                            Content = bugViewModel.SeverityIndex,
                            Foreground = Brushes.Black,
                            FontWeight = FontWeights.Bold,
                            FontSize = 16,
                            HorizontalContentAlignment = HorizontalAlignment.Center,
                            VerticalContentAlignment = VerticalAlignment.Center,
                            HorizontalAlignment = HorizontalAlignment.Center,
                            VerticalAlignment = VerticalAlignment.Center,
                            Width = 24,
                            Height = 24,
                            Padding = new Thickness(0),
                        });
            }

            Grid.Children.Add(stackPanel);

        }


        private void CreateTaskChildsSmall(IEnumerable<TaskViewModel> tasks)
        {
            double time = 0;
            Brush brush;
            if (ElementManager.IsClosedState(_storyState))
            {
                time = Math.Min(MaxHours, tasks.Sum(p => p.CompletedWork.GetValueOrDefault(0)));
                brush = (Brush)Grid.Resources["ColorGreen"];
            }
            else
            {
                time = Math.Min(MaxHours, tasks.Sum(p => p.RemainingWork.GetValueOrDefault(0)));
                brush = (Brush)Grid.Resources["ColorRed"];
            }
            Grid grid = new Grid();
            grid.ColumnDefinitions.Add(new ColumnDefinition(){Width= new GridLength(time/100,GridUnitType.Star)});
            grid.ColumnDefinitions.Add(new ColumnDefinition(){Width= new GridLength(1-time/100,GridUnitType.Star)});
            var rectangle = new Rectangle() { Opacity = 0.80, Fill = brush, Stroke = Brushes.Black, VerticalAlignment = VerticalAlignment.Stretch, HorizontalAlignment = HorizontalAlignment.Stretch, Margin = new Thickness(0, 5, 0, 5) };            
            grid.Children.Add(rectangle);
            if (Math.Abs(time - MaxHours) < 0.1)
            {
                Cross.Visibility = System.Windows.Visibility.Visible;
            }
            Grid.Children.Add(grid);
        }

        private void CreateChilds(IList<IScrumItemViewModel<DomainBase>> items)
        {
            
            PlacedControls.UnionToLeft(items);
            PlacedControls.Sort(x=>x.Sorting);
        }

        /// <summary>
        /// Releases managed (c# or .net) resources.
        /// </summary>
        protected override void ReleaseManagedResources()
        {
            if (StackedUserStory != null)
            {
                //StackedUserStory.Tasks.CollectionChanged -= OnTaskBugCollectionChanged;
                //StackedUserStory.Bugs.CollectionChanged -= OnTaskBugCollectionChanged;

            }
            ScrumViewModelData scrumData = ((AppScreen)(Application.Current.MainWindow)).Container.Resolve<ScrumViewModelData>();
            scrumData.DataContext.ElementChanged -= OnContextElementChanged;
            scrumData.DataContext.CollectionChanged -= OnContextCollectionChanged;

            base.ReleaseManagedResources();
            
        }

        private void CollectionChanged(DomainCollectionChangedEventArgs childEvent)
        {
            if (childEvent.Owner == StackedUserStory.Tasks || childEvent.Owner == StackedUserStory.Bugs)
            {
                Init();
            }
        }

        private void BringItemToFront(object sender)
        {
            var cont = ViewElementUtils.FindVisualChild<WrapPanelAnimated>(ItemContainerControl);
            var uiElement = (FrameworkElement)sender;

            foreach (FrameworkElement children in cont.Children)
            {
                Grid.SetZIndex(children, 0);
                if (children.DataContext == uiElement.DataContext)
                {
                    children.SetValue(Canvas.ZIndexProperty, 999);
                }
            }
        }


        
        #endregion

        #region events


        private void OnUserStoryControlLoaded(object sender, RoutedEventArgs e)
        {
            InitializeComponent();
            ItemContainerControl.Width = ActualWidth;
            Loaded -= OnUserStoryControlLoaded;
            Init();
        }

       
        private void OnContextCollectionChanged(object sender, DomainCollectionChangedEventArgs e)
        {
            if (e is MultipleDomainCollectionChangedEventArgs)
            {
                MultipleDomainCollectionChangedEventArgs args = (MultipleDomainCollectionChangedEventArgs)e;
                foreach (var childEvent in args.Children)
                {
                    CollectionChanged(childEvent);
                }
            }
            else
            {
                CollectionChanged(e);
            }
        }

        
        void OnStackedUserStoryControlDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if (DataContext is UserStoryViewModel)
            {
                StackedUserStory = (UserStoryViewModel)DataContext;
                
            }
            else
            {
                StackedUserStorie = null;                
            }
        }


        private void OnDrop(object sender, Microsoft.Surface.Presentation.SurfaceDragDropEventArgs e)
        {
            if (CanDrop(e.Cursor.Data) != CanDropResult.CanDrop)  { return; }

            if (e.Cursor.Data is TaskViewModel)
            {
                var story = e.Cursor.Data as TaskViewModel;
                using (story.Original.Context.UndoManager.CaptureUndoRedoAction(story.Name))
                {
                  
                    ((TaskViewModel) e.Cursor.Data).State = StoryState;
                  
                    if (StackedUserStory.Original.Id != ((TaskViewModel) e.Cursor.Data).Original.Parent.Id)
                    {
                        StackedUserStory.Tasks.Add(((TaskViewModel) e.Cursor.Data).Original);
                    }
                }

            }
            if (e.Cursor.Data is BugViewModel)
            {
                var bug = e.Cursor.Data as BugViewModel;
                using (bug.Original.Context.UndoManager.CaptureUndoRedoAction(bug.Name))
                {
                    ((BugViewModel) e.Cursor.Data).State = StoryState;
                   
                    if (StackedUserStory.Original.Id != ((BugViewModel)e.Cursor.Data).Original.Parent.Id)
                    {
                        StackedUserStory.Bugs.Add(((BugViewModel)e.Cursor.Data).Original);
                    }
                }

            }
            else if (e.Cursor.Data is UserStoryViewModel)
                ((UserStoryViewModel)e.Cursor.Data).State = StoryState;
            
            e.Effects = DragDropEffects.None;
        }
        
        private void OnContextElementChanged(object sender, PropertyChangedEventArgs e)
        {
            
            var args = e as DomainChangedEventArgs;
            if (args == null) return;
            if (args.ContainsElementId(StackedUserStory.Id, false))
            {
                if (args.ContainsPropertyNames("CompletedWork", "RemainingWork", "State", "Priority"))
                {
                    Init();
                }
            }
            else if (args.ContainsElementId(StackedUserStory.Id, true))
            {
                if (args.ContainsPropertyNames("CompletedWork", "RemainingWork", "State", "Priority", "Severity"))
                {
                    Init();
                }
            }
        }


        private void OnItemControlTouchDown(object sender, System.Windows.Input.TouchEventArgs e)
        {
            e.Handled = true;
        }

        private void OnItemControlMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            e.Handled = true;
        }

        private void OnItemPreviewDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            BringItemToFront(sender);
        }


        private void OnItemPreviewDown(object sender, System.Windows.Input.TouchEventArgs e)
        {
            BringItemToFront(sender);
        }

        #endregion


        #region IDropUserControl Members

        public FrameworkElement GetRootControl
        {
            get { return Grid; }
        }

        public bool ShowIconWithbackground
        {
            get { return true; }
        }

        public CanDropResult CanDrop(object objectToDrop)
        {
            return BugViewModel.CanChangeState(objectToDrop, StoryState) | UserStoryViewModel.CanChangeState(objectToDrop, StoryState) | TaskViewModel.CanChangeState(objectToDrop, StoryState);
        }

        #endregion

    }
}



  
